package pl.edu.pb.wi.pwnography.controller;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import javax.validation.Valid;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import pl.edu.pb.wi.pwnography.model.form.MasterForm;
import pl.edu.pb.wi.pwnography.model.form.StandarizationForm;
import pl.edu.pb.wi.pwnography.modules.Standarization;
import pl.edu.pb.wi.pwnography.session.FileList;

@Controller
@RequestMapping("/module/standarization")
public class StandarizationModule {
    private static final Logger log = Logger
	    .getLogger(StandarizationModule.class.getName());

    private static final String STANDARIZATION_ERROR = "W trakcie przeprowadzania standaryzacji wystąpił błąd.";
    private static final String NORMALIZATION_DESCRIPTION = "Normalizacja przeprowadzona dla kolumny %s.";
    private static final String NORMALIZATION_SUCCESS = "Normalizacja dla kolumny %s przebiegła pomyślnie.";
    private static final String MINMAX_DIFF_ERROR = "Wartości minimum i maksimum muszą być różne.";
    private static final String MINMAX_MAX_LT_MIN_ERROR = "Wartość maksymalna nie może być mniejsza od minimalnej.";
    private static final String MINMAX_MIN_GT_MAX_ERROR = "Wartość minimalna nie może być większa od maksymalnej.";
    private static final String MINMAX_FIELD_NULL_ERROR = "Wpisz wartość.";
    private static final String MINMAX_DESCRIPTION = "Standaryzacja min-max dla kolumny %s. Minimum - %f Maximum - %f";
    private static final String MINMAX_SUCCESS = "Standaryzacja min-max dla kolumny %s, minimum %f oraz maksimum %f, przebiegła pomyślnie.";

    @Autowired
    private FileList fileList;

    public void setFileList(FileList fileList) {
	this.fileList = fileList;
    }

    @ModelAttribute("floatColumnList")
    public List<String> getFloatColumnNames() {
	return fileList.getActiveFile().getFloatTypeColumnNames();
    }

    @RequestMapping(value = "normalization", method = RequestMethod.GET)
    public String normalization(Model model) {
	log.info("Standarization normalization GET.");

	model.addAttribute("form", new MasterForm());

	return "module/standarization/normalization";
    }

    @RequestMapping(value = "normalization", method = RequestMethod.POST)
    public String normalization(@ModelAttribute("form") @Valid MasterForm form,
	    BindingResult results, Model model) {
	log.info("Standarization normalization POST.");

	if (results.hasErrors()) {
	    return "module/standarization/normalization";
	}

	try {
	    Map<String, List<Object>> data = Standarization.normalization(
		    form.getColumnName(),
		    fileList.getActiveFile().getColumnValues(
			    form.getColumnName()), form.getResultColumnName());

	    String description = String.format(NORMALIZATION_DESCRIPTION,
		    form.getColumnName());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(NORMALIZATION_SUCCESS,
			    form.getColumnName()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Problem with standarization normalization. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { STANDARIZATION_ERROR }));
	}

	return "module/standarization/normalization";
    }

    @RequestMapping(value = "minmax", method = RequestMethod.GET)
    public String minmax(Model model) {
	log.info("Standarization min-max GET.");

	model.addAttribute("form", new StandarizationForm());

	return "module/standarization/minmax";
    }

    @RequestMapping(value = "minmax", method = RequestMethod.POST)
    public String minmax(
	    @ModelAttribute("form") @Valid StandarizationForm form,
	    BindingResult results, Model model) {
	log.info("Standarization min-max POST.");

	if (results.hasErrors()) {
	    return "module/standarization/minmax";
	}

	if (form.getMin() == null)
	    results.addError(new FieldError("minMax", "min",
		    MINMAX_FIELD_NULL_ERROR));
	if (form.getMax() == null)
	    results.addError(new FieldError("minMax", "max",
		    MINMAX_FIELD_NULL_ERROR));
	else {
	    if (form.getMin() == form.getMax()) {
		results.addError(new FieldError("minMax", "min",
			MINMAX_DIFF_ERROR));
		results.addError(new FieldError("minMax", "max",
			MINMAX_DIFF_ERROR));
	    }
	    if (form.getMin() > form.getMax()) {
		results.addError(new FieldError("minMax", "min",
			MINMAX_MIN_GT_MAX_ERROR));
		results.addError(new FieldError("minMax", "max",
			MINMAX_MAX_LT_MIN_ERROR));
	    }
	}

	if (results.hasErrors()) {
	    return "module/standarization/minmax";
	}

	try {
	    Map<String, List<Object>> data = Standarization.minMax(
		    form.getColumnName(),
		    fileList.getActiveFile().getColumnValues(
			    form.getColumnName()), form.getMin(),
		    form.getMax(), form.getResultColumnName());

	    String description = String.format(MINMAX_DESCRIPTION,
		    form.getColumnName(), form.getMin(),
		    form.getMax());

	    fileList.getActiveFile().addNewRevision(data, description);

	    log.info(fileList.getActiveFile().getCurrentRevisionData()
		    .toString());

	    model.addAttribute("successMsgs", Arrays
		    .asList(new String[] { String.format(MINMAX_SUCCESS,
			    form.getColumnName(), form.getMin(),
			    form.getMax()) }));
	} catch (Exception e) {
	    log.info(String.format(
		    "Problem with standarization min-max. Exception: %s",
		    e.getMessage()));

	    model.addAttribute("errorMsgs",
		    Arrays.asList(new String[] { STANDARIZATION_ERROR }));
	}

	return "module/standarization/minmax";
    }

}
